package com.chungkui.bond.microservice.resource.config;

import com.chungkui.bond.microservice.client.CheckClientRunner;
import com.chungkui.bond.microservice.client.InitRelationship;
import com.chungkui.bond.microservice.resource.cache.PermissionCache;
import com.chungkui.bond.microservice.resource.cache.PermissionCacheImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2ClientProperties;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.UnanimousBased;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.web.client.RestTemplate;
import com.chungkui.bond.microservice.resource.controller.PermissionCacheController;
import java.util.Arrays;
import java.util.List;

/**
 * 资源服务器配置改写类
 *
 * @author jason
 */
@Configuration
@EnableResourceServer
public class BondResourceServerConfigurerAdapter extends ResourceServerConfigurerAdapter {


    @Autowired
    private ResourceServerProperties resourceServerProperties;

    @Autowired
    private OAuth2ClientProperties oAuth2ClientProperties;

    @Autowired
    RestTemplate restTemplate;


    /**
     * 校验属于哪个端点的资源
     *
     * @return
     */
    @Bean
    public ResourceServerTokenServices tokenServices() {
        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
        UserAuthenticationConverter userTokenConverter = new CommonUserConverter();
        /**
         * token携带认证信息解析器 todo 改成加密方案
         */
        accessTokenConverter.setUserTokenConverter(userTokenConverter);
        remoteTokenServices.setCheckTokenEndpointUrl(resourceServerProperties.getTokenInfoUri());
        remoteTokenServices.setClientId(oAuth2ClientProperties.getClientId());
        remoteTokenServices.setClientSecret(oAuth2ClientProperties.getClientSecret());
        remoteTokenServices.setRestTemplate(restTemplate);
        remoteTokenServices.setAccessTokenConverter(accessTokenConverter);
        return remoteTokenServices;
    }


    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http
                .authorizeRequests();

        registry.anyRequest().authenticated().accessDecisionManager(accessDecisionManager());
    }

    @Bean
    public AccessDecisionManager accessDecisionManager() {
        // 构造一个新的AccessDecisionManager 放入两个投票器
        WebExpressionVoter webExpressionVoter= new WebExpressionVoter();
        webExpressionVoter.setExpressionHandler(new OAuth2WebSecurityExpressionHandler());
        BondAccessDecisionVoter bondAccessDecisionVoter=new BondAccessDecisionVoter();
        bondAccessDecisionVoter.setPermissionCache(permissionCache());
        List<AccessDecisionVoter<?>> decisionVoters = Arrays.asList(webExpressionVoter,bondAccessDecisionVoter);
        return new UnanimousBased(decisionVoters);
    }
    @Bean
   public InitRelationship initRelationship(){
        return new InitRelationship();
    }
    @Bean
    public PermissionCacheController permissionCacheController(){
        return new PermissionCacheController();
    }
    @Bean
    CheckClientRunner checkClientRunner(){
        return new CheckClientRunner();
    }
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.tokenServices(tokenServices());
        resources.accessDeniedHandler(new BondAccessDeniedHandler());
    }
    @Bean
    @DependsOn("restTemplate")
    PermissionCache permissionCache(){
        return new PermissionCacheImpl(oAuth2ClientProperties.getClientId());
    }
}